import os
import subprocess
import platform
import folder_paths
from server import PromptServer
from aiohttp import web
import json


class OpenPathNode:
    """
    A ComfyUI node that takes a path string as input and provides a button to open it in the default file explorer.
    """

    # Class variable to store last executed paths by node ID
    _last_executed_paths = {}

    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {},
            "optional": {
                "path": ("STRING", {
                    "default": "",
                    "multiline": False,
                    "placeholder": "Enter file or folder path...",
                    "forceInput": False  # Allows both connection and manual input
                }),
            },
        }

    RETURN_TYPES = ("STRING",)
    RETURN_NAMES = ("path",)
    FUNCTION = "open_path"
    CATEGORY = "Grover/System"
    OUTPUT_NODE = True

    def open_path(self, path=""):
        """Process the path and return it (the button action is handled on the frontend)"""
        # Ensure we have a valid string path
        if path is None:
            path = ""

        path_str = str(path)

        # Store the last executed path for this node instance
        # We'll use a combination of the path and current time as a simple ID
        import time
        node_key = f"{id(self)}_{int(time.time())}"
        OpenPathNode._last_executed_paths[node_key] = path_str

        # Also store with a simpler key based on the path content for lookup
        if path_str:
            OpenPathNode._last_executed_paths[f"path_{hash(path_str)}"] = path_str
        return (path_str,)

    @classmethod
    def get_last_executed_path(cls, path_hint=""):
        """Get the last executed path, optionally filtered by a hint"""
        if not cls._last_executed_paths:
            return None

        # If we have a specific path hint, try to find it
        if path_hint:
            path_key = f"path_{hash(path_hint)}"
            if path_key in cls._last_executed_paths:
                return cls._last_executed_paths[path_key]

        # Otherwise return the most recent one
        # Get all non-hash keys (the timestamped ones)
        timestamped_keys = [
            k for k in cls._last_executed_paths.keys() if not k.startswith("path_")]
        if timestamped_keys:
            # Sort by timestamp (last part of the key) and get the most recent
            latest_key = max(timestamped_keys,
                             key=lambda x: int(x.split('_')[-1]))
            return cls._last_executed_paths[latest_key]

        return None    @ staticmethod

    def open_file_explorer(path):
        """Open the given path in the default file explorer"""
        try:
            # Normalize the path
            normalized_path = os.path.normpath(path)

            # Check if path exists
            if not os.path.exists(normalized_path):
                print(f"Path does not exist: {normalized_path}")
                return False

            # Get the system platform
            system = platform.system()

            if system == "Windows":
                # Windows - use explorer
                # Note: Don't use check=True as explorer can return non-zero exit codes even on success
                if os.path.isfile(normalized_path):
                    # If it's a file, select it in explorer
                    result = subprocess.run(
                        ['explorer', '/select,', normalized_path], capture_output=True)
                    # For files, we can check if explorer process started successfully
                    # Only treat severe errors (>1) as failures
                    if result.returncode > 1:
                        print(
                            f"Explorer returned code {result.returncode} for file: {normalized_path}")
                        print(
                            f"stderr: {result.stderr.decode() if result.stderr else 'None'}")
                        return False
                else:
                    # If it's a directory, open it
                    result = subprocess.run(
                        ['explorer', normalized_path], capture_output=True)
                    # For directories, explorer often returns 1 even on success, so only fail on severe errors
                    # Only treat severe errors (>1) as failures
                    if result.returncode > 1:
                        print(
                            f"Explorer returned code {result.returncode} for directory: {normalized_path}")
                        print(
                            f"stderr: {result.stderr.decode() if result.stderr else 'None'}")
                        return False
            elif system == "Darwin":  # macOS
                # macOS - use open command
                subprocess.run(['open', normalized_path], check=True)
            elif system == "Linux":
                # Linux - try various file managers
                try:
                    subprocess.run(['xdg-open', normalized_path], check=True)
                except FileNotFoundError:
                    # Fallback to other common file managers
                    for fm in ['nautilus', 'dolphin', 'thunar', 'pcmanfm']:
                        try:
                            subprocess.run([fm, normalized_path], check=True)
                            break
                        except FileNotFoundError:
                            continue
                    else:
                        print("No suitable file manager found for Linux")
                        return False
            else:
                print(f"Unsupported operating system: {system}")
                return False

            return True

        except Exception as e:
            print(f"Error opening path '{path}': {str(e)}")
            return False


# Web endpoint for handling button clicks
@PromptServer.instance.routes.post("/grover/open_path")
async def open_path_endpoint(request):
    """Handle the open path button click from the frontend"""
    try:
        data = await request.json()
        path = data.get("path", "")

        # If no direct path provided, try to get the last executed path
        if not path or path.strip() == "":
            last_path = OpenPathNode.get_last_executed_path()
            if last_path:
                path = last_path
            else:
                return web.json_response({
                    "success": False,
                    "error": "No path available. Please execute the workflow first (Queue Prompt) or enter a path manually."
                })

        success = OpenPathNode.open_file_explorer(path.strip())

        if success:
            return web.json_response({"success": True, "message": f"Opened path: {path}"})
        else:
            return web.json_response({"success": False, "error": f"Failed to open path: {path}"})

    except Exception as e:
        return web.json_response({"success": False, "error": str(e)})


# Node registration
NODE_CLASS_MAPPINGS = {
    "OpenPathNode": OpenPathNode
}

NODE_DISPLAY_NAME_MAPPINGS = {
    "OpenPathNode": "📁 Open Path"
}
